home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / info-service / gopher / Unix / GopherTools / glog / glog23.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-22  |  20.1 KB  |  796 lines

  1. /*** glog 2.3 ***/
  2.  
  3. /*** glog.c -- analysis    tool for Unix gopherd logs ***/
  4.  
  5. /***
  6.  *** Usage : glog [-d [0,1,2,3,4]] [-p plot_number] -U < logfile > reportfile {2>plot_directives}
  7.  ***/
  8.  
  9. /*** Description: glog munges through a    Unix gopherd log and extracts
  10.  *** important looking statistics. It catalogs all hosts that have connected
  11.  *** to    the gopherd during the logging period and sorts    them according to the
  12.  *** number of accesses. It does the same for each directory and file accessed,
  13.  *** and ranks them according to popularity.
  14.  ***   Depending on the    argument to the    -d option, glog    will generate varying
  15.  *** levels of detailed    reports. The levels of detail are:
  16.  ***    0 -- (default) Total number of hosts and connections only.
  17.  ***    1 -- All hosts and all data sorted and unsorted.
  18.  ***    2 -- All data accessed by each host and    all hosts accessing each entry.
  19.  ***    3 -- Print Exception/Problem Report only.
  20.  ***    4 -- Output plot points    for GNUPlot (or    whatever you want to use)
  21.  ***         This mode also outputs GNUplot directives to stderr. See
  22.  ***         the last few lines    of Plotter() to    change the way the
  23.  ***         plots look.
  24.  ***
  25.  *** Numeric arguments to "-p" indicate the type of plot to be produced.
  26.  ***   Currently, -p 0 produces the same output as if -d 4 was selected.
  27.  ***
  28.  *** -U  get rid of "useless" information.  ie. only print sorted info
  29.  ***
  30.  *** Note: "glog" is the same as "glog -d" is the same as "glog    -d 0"
  31.  ***/
  32.  
  33. /*** Version 2.3
  34.  *** by: Andy Wick - awick@csugrad.cs.vt.edu
  35.  ***             4/3/93
  36.  ***
  37.  *** - Fixed ProcessLine to handle paths with spaces, ftp, and other things.
  38.  *** Made it more readable/understandable. "/" is now the same thing as a
  39.  *** root connection.
  40.  *** - Added -U option (Ugly)
  41.  *** - Fixed the last line being processed twice
  42.  ***
  43.  ***/
  44.  
  45. /***
  46.  *** Version 2.2
  47.  *** by: Chuck Shotton - cshotton@oac.hsc.uth.tmc.edu
  48.  ***                     1/4/93
  49.  ***
  50.  *** - Cleaned up argument parsing.
  51.  *** - Added support for multiple plots. (No new plots were implemented though.)
  52.  *** - Made the data field in NODE_RECs dynamic, based on the actual data size.
  53.  ***/
  54.  
  55. /***
  56.  *** Version 2.1 
  57.  *** by: Michael Mealling - Georgia Institute of Technology
  58.  ***                Office of Information Technology
  59.  ***                michael.meallingl@oit.gatech.edu
  60.  ***                12/29/92
  61.  ***
  62.  ***  Added a list per each node so that we can    see exactly who    is accessing
  63.  ***  what. Each node contains a linked    list holding who accessed it or
  64.  ***  what was accessed    depending on which list    you are    talking    about (hosts
  65.  ***  or docs).    This is    switchable with    a -d option to glog.
  66.  ***
  67.  ***  Also added a very    hugly hack for filtering unknown log entries. Since
  68.  ***  these can    be very    important if your server is sick I've added these
  69.  ***  entries to an Exception/Problem Report that is printed at    the end
  70.  ***  of a detail 2 report. This report    can be printed alone by    specifying
  71.  ***  a    detail 3 report.
  72.  ***  
  73.  ***  Also added in Brygg Ulmers plotting stuff    so that    we can get nice
  74.  ***  plots from GNUplot. This is not very robust right    now.
  75.  ***/
  76.  
  77. /***
  78.  *** Versions 1.0
  79.  *** by: Chuck Shotton - U of Texas Health Science Center - Houston,
  80.  ***             Office    of Academic Computing
  81.  ***             cshotton@oac.hsc.uth.tmc.edu
  82.  ***             6/17/92
  83.  ***/
  84.  
  85.  
  86. #include <stdio.h>
  87. #include <string.h>
  88. #include <stdlib.h>
  89. #ifdef THINK_C
  90. #include <console.h>
  91. #endif
  92.  
  93. #define    GLOG_VERSION "Gopher Log Analyzer v.2.3\n"
  94.  
  95. /*******************************/
  96. /*** The following 2 defines adjust the    amount of memory allocated for
  97.  *** A)    the data contained in each information node and
  98.  *** B)    the size of input lines.
  99.  *** They are inside conditionals to allow command-line    or Make    file
  100.  *** specification of their size (i.e. cc -DNODE_DATA_SIZE=2048).
  101.  *** WARNING: For now, they should be the same size!!! (InsertDetail, etc.
  102.  ***          needs some strcpys replaced with strncpys    to avoid data overrun.
  103.  ***/
  104.  
  105. #ifndef    NODE_DATA_SIZE
  106. #define    NODE_DATA_SIZE 1024
  107. #endif
  108.  
  109. #ifndef    LINE_SIZE
  110. #define    LINE_SIZE 1024
  111. #endif
  112.  
  113. /*******************************/
  114. /***
  115.  *** Detail list. I could have used the    left half of the tree but it seemed
  116.  *** confusing when I added the    detail list. I fully intended to rewrite the 
  117.  *** sorted list by never got around to    it.
  118.  ***/
  119. typedef    struct node_list {
  120.     char *data;
  121.     int hits;
  122.     struct node_list *next;
  123. } NODE_LIST;
  124.  
  125. typedef    NODE_LIST *LIST_PTR;
  126.  
  127.  
  128. /***
  129.  *** Main tree:    used both as the main tree and the sorted list
  130.  ***/
  131. typedef    struct node_rec    {
  132.     char *data;
  133.     LIST_PTR llist;
  134.     int hits;
  135.     struct node_rec    *left, *right;
  136. } NODE_REC;
  137.  
  138. typedef    NODE_REC *NODE_PTR;
  139.  
  140.  
  141. /***
  142.  *** The cruft list is a general list for things that aren't parse-able    by
  143.  *** ProcessLine(). It will be printed at the end of detail 2 listing.
  144.  *** and only by a detail 3 listing.
  145.  *** This does seem to be an awful silly thing to have to do.
  146.  ***/
  147.  
  148. NODE_PTR hosts,    docs;
  149. LIST_PTR cruft;
  150. char day[4], month[4], date[3],    hours[9], year[5], pid[6],
  151.     hostname[120], message1[25], message2[LINE_SIZE], path[LINE_SIZE];
  152. char start_date[20], stop_date[20];
  153. int detail, plot_num, USELESS = 1;
  154.  
  155. /*******************************/
  156.  
  157. main(argc, argv)
  158. int argc;
  159. char **argv;
  160. {
  161. char line[LINE_SIZE];
  162. int i;
  163.  
  164. #ifdef THINK_C
  165.     argc = ccommand(&argv);
  166. #endif
  167. /***
  168.  *** This was nasty. It's been redone into a case. Hi Ho!
  169.  ***/
  170.      plot_num = -1;
  171.      detail = 0;
  172.      i = 1;
  173.      while (i<argc) {
  174.          switch (argv[i][1]) {
  175.              case 'd':
  176.                  if (i<argc-1) {
  177.                      detail = atoi(argv[++i]);
  178.                  }
  179.                  
  180.                  if (detail>4 || detail<0) detail = 0;
  181.                  
  182.                  if (plot_num >= 0) {
  183.                      fprintf(stderr, "Warning: Details override plots. No data will be plotted!\n");
  184.                      plot_num = -1;
  185.                  }
  186.                  break;
  187.                  
  188.              case '?':
  189.              case 'h':
  190.                  PrintHelp();
  191.                 break;
  192.             
  193.             case 'p': /*custom plots*/
  194.                  if (i<argc-1) {
  195.                      plot_num = atoi(argv[++i]);
  196.                  }
  197.                 break;
  198.             
  199.             case 'U':
  200.                 USELESS = 0;
  201.                 break;
  202.             default:
  203.                 PrintHelp();
  204.                 break;
  205.         } /*switch*/
  206.         
  207.         i++; /*next arg...*/
  208.         
  209.     } /*while*/
  210.                 
  211.     if (detail < 4 && plot_num<0) {
  212.         printf(GLOG_VERSION);
  213.         Initialize();
  214.  
  215.         fgets(line, LINE_SIZE, stdin);
  216.         ProcessLine(line);
  217.         sprintf(start_date, "%s    %s, %s", month,    date, year);
  218.     
  219.         while (!feof(stdin)) {
  220.             fgets(line, LINE_SIZE, stdin);
  221.             if (feof(stdin))
  222.                break;
  223.             ProcessLine(line);
  224.         }
  225.     
  226.         sprintf(stop_date, "%s %s, %s",    month, date, year);
  227.     
  228.         ShowStats();
  229.     }
  230.     else {
  231.         if (detail == 4) plot_num = 0; /*handle the -d 4 case for compatibility*/
  232.         Plotter(plot_num);
  233.     }
  234.     exit(0);
  235. }
  236.  
  237. /*******************************/
  238.  
  239. Initialize()
  240. {
  241.     hosts =    docs = NULL;
  242.     cruft =    NULL;
  243. }
  244.  
  245. /*******************************/
  246.  
  247. PrintHelp()
  248. {
  249.     fprintf(stderr,"Usage: glog -U [-d [0,1,2,3,4]] [-p [0-1]\n");
  250.     fprintf(stderr," stdin should be a gopher log. stdout will be a formatted\n");
  251.     fprintf(stderr," report or plot points. stderr will be errors or plot directives.\n");
  252.     fprintf(stderr, "-U remove useless information\n");
  253.     fprintf(stderr,"-d arguments:\n");
  254.     fprintf(stderr," 0 - Total hosts & connections\n");
  255.     fprintf(stderr," 1 - All hosts & data accesses, sorted & unsorted\n");
  256.     fprintf(stderr," 2 - All data by host & vice versa\n");
  257.     fprintf(stderr," 3 - Exception/Problem report\n");
  258.     fprintf(stderr," 4 - Monthly usage plot (data to stdout, directives to stderr)\n");
  259.     exit(-1);
  260. }
  261.  
  262. /*******************************/
  263. char *getf(char *temp, char *field)
  264. {
  265.    while(isspace(*temp))
  266.       temp++;
  267.  
  268.    while (!isspace(*temp))
  269.      *field++ = *temp++;
  270.  
  271.    *field = '\0';
  272.  
  273.    return(temp);
  274. }
  275. /*******************************/
  276. /* Read    a line from the    log file, parse    it up, and insert the */
  277. /* info    into the appropriate tables.                  */
  278.  
  279. ProcessLine(line)
  280. char *line;
  281. {
  282. int i;
  283. char *temp;
  284.  
  285. /*** 
  286.  *** This is a filter for Code:    type messages that I cannot figure out
  287.  *** what in the hell to do with so I'll stick 'em in cruft.
  288.  ***/
  289.     temp = line;
  290.         temp = getf(temp, day);
  291.     if (strstr("MonTueWedThuFriSatSun",day) == NULL) 
  292.         InsertDetail(&(cruft),line);
  293.         else {
  294.  
  295. /***
  296.  *** Scan the line into    it's respective    parts if everything is ok (so far)
  297.  ***/
  298.         path[0] = '\0';
  299.             temp = getf(temp, month);
  300.         temp = getf(temp, date);
  301.         temp = getf(temp, hours);
  302.         temp = getf(temp, year);
  303.         temp = getf(temp, pid);
  304.         temp = getf(temp, hostname);
  305.         if (hostname[0] == ':')
  306.            return;
  307.         temp = getf(temp, message1); /* : COLON */
  308.         temp = getf(temp, message1);
  309.         temp = getf(temp, message2);
  310.                while(isspace(*temp))
  311.                    temp++;
  312.         strcpy(path, temp);
  313.         path[strlen(path)-1] = '\0';
  314.  
  315.  
  316. /***
  317.  *** This one is for that annoying 0.0.0.1 IP address then gets    stuck
  318.  *** in    the log    when someone is    trying to access something you ain't got
  319.  ***/
  320.  
  321.         if (strcmp(hostname,"0.0.0.1"))    {
  322.  
  323. /*** 
  324.  *** And this one goes with the    aboves error message which has
  325.  *** quotes in it that throw off the sscanf
  326.  ***/
  327.  
  328.     
  329.             if (strcmp(message1, "Root") == 0)
  330.             {
  331.                 Insert(&hosts, hostname, "Root Connections");
  332.                 Insert(&docs, "Root Connections", hostname);
  333.             }
  334.             else if ((strcmp(message1, "retrieved") == 0) && (strcmp(path, "/") == 0))
  335.             {
  336.                 Insert(&hosts, hostname, "Root Connections");
  337.                 Insert(&docs, "Root Connections", hostname);
  338.             }
  339.             else if (strncmp(message2, "ftp:", 4) == 0)
  340.             {
  341.                 Insert(&hosts, hostname, message2);
  342.                 Insert(&docs, message2, hostname);
  343.             }
  344.             else if (strcmp(message1, "retrieved") == 0)
  345.             {
  346.                    if (path[0] == '\0')
  347.                           return;
  348.                 Insert(&docs, path, hostname);
  349.                 Insert(&hosts, hostname, path);
  350.             }
  351.             else /* wasn't a retrieval */
  352.             {
  353.                 InsertDetail(&(cruft),line);
  354.             }
  355.  
  356.         } /*0.0.0.1 Match*/
  357.         else {
  358.             InsertDetail(&(cruft),line);
  359.         }
  360.     } /*Day Match*/
  361. }
  362.  
  363. /*******************************/
  364. /* Insert a raw    line into the cruft list. */
  365.  
  366. InsertCruft(list, data)
  367. LIST_PTR *list;
  368. char *data;
  369. {
  370. LIST_PTR temp;
  371.  
  372.     if(*list == NULL) {
  373.         temp = (LIST_PTR) malloc(sizeof(NODE_LIST));
  374.         if (temp) {
  375.             temp->next = NULL;
  376.             if (!(temp->data = malloc(strlen(data)+1))) {
  377.                 fprintf(stderr, "ERROR: Out of memory in InsertCruft\n");
  378.                 exit(1);
  379.             }
  380.             else {
  381.                 strcpy(temp->data,data);
  382.                 *list =    temp;
  383.             }
  384.         }
  385.         else 
  386.             printf("Memory error!/n");
  387.     }
  388.     else
  389.         InsertCruft(&((*list)->next),data);
  390. }
  391.  
  392. /*******************************/
  393. /* Insert tree_element into the    appropriate symbol table. Increment the    */
  394. /* number of hits if that element is already present.            */
  395. /* Insert list_element into linked list    contained in the node that    */
  396. /* tree_element    was put    in.                        */
  397.  
  398. Insert(tree, tree_element, list_element)
  399. NODE_PTR *tree;
  400. char *tree_element;
  401. char *list_element;
  402. {
  403. NODE_PTR temp;
  404. int i;
  405.     if (*tree == NULL) {
  406.         temp = (NODE_PTR) malloc(sizeof(NODE_REC));
  407.         if (temp) {
  408.             temp->left = temp->right = NULL;
  409.             temp->hits = 1;
  410.             
  411.             if (!(temp->data = malloc(strlen(tree_element)+1))) {
  412.                 fprintf(stderr, "ERROR: Out of memory in Insert\n");
  413.                 exit(1);
  414.             }
  415.             else {
  416.                 strcpy (temp->data, tree_element);
  417.                 temp->llist = NULL;
  418.                 InsertDetail(&(temp->llist), list_element);
  419.                 *tree =    temp;
  420.             }
  421.         }
  422.         else
  423.             printf("Memory error\n");
  424.     }
  425.     else {
  426.         i=strcmp(tree_element, (*tree)->data);
  427.         if (i >    0)
  428.             Insert(&((*tree)->right), tree_element,    list_element);
  429.         else if    (i<0) 
  430.             Insert(&((*tree)->left), tree_element, list_element);
  431.         else {
  432.             (*tree)->hits += 1;
  433.             InsertDetail(&((*tree)->llist),    list_element);
  434.         }
  435.     }
  436. }
  437.  
  438. /*******************************/
  439. int total_hits,    total_nodes;
  440. NODE_PTR by_num;
  441.  
  442. /*******************************/
  443. /* Dump    out the    contents of the    given symbol table and sort by */
  444. /* number of "hits" on the fly.                       */
  445.  
  446. DumpTree(tree)
  447. NODE_PTR tree;
  448. {
  449.     if (tree == NULL) 
  450.         return;
  451.     else {
  452.         DumpTree(tree->left);
  453.         if ((detail == 1) || (detail ==    2)) {
  454.             if (USELESS)
  455.                 printf("%-60.60s %5d\n", tree->data, tree->hits);
  456.             if (detail > 1)
  457.                 DumpDetailList(tree->llist);
  458.         }
  459.         total_hits += tree->hits;
  460.         total_nodes++;
  461.         InsertByNum(tree);
  462.         DumpTree(tree->right);
  463.     }
  464. }
  465.  
  466. /*******************************/
  467.  
  468. DumpStats(tree)
  469. NODE_PTR tree;
  470. {
  471.     total_hits = 0;
  472.     total_nodes= 0;
  473.     by_num = NULL;
  474.     DumpTree(tree);
  475. }
  476.  
  477. /*******************************/
  478. /* Turn    a tree node into an element in a linked    list */
  479.  
  480. InsertByNum(node)
  481. NODE_PTR node;
  482. {
  483. NODE_PTR temp, temp2;
  484.     if (by_num == NULL) {
  485.         by_num = node;
  486.         node->left == NULL;
  487.     }
  488.     else {
  489.         temp = by_num;
  490.         temp2 =    temp->left;
  491.         if (node->hits >= temp->hits) {
  492.             node->left = temp;
  493.             by_num = node;
  494.         }
  495.         else {
  496.             while (temp2 !=    NULL) {
  497.                 if (node->hits > temp2->hits) {
  498.                     temp->left = node;
  499.                     node->left = temp2;
  500.                     return;
  501.                 }
  502.                 else {
  503.                     temp = temp2;
  504.                     temp2 =    temp->left;
  505.                 }
  506.             }
  507.             temp->left = node;
  508.             node->left = NULL;
  509.         }
  510.     }
  511. }
  512.  
  513. /*******************************/
  514. /* Dump    out the    linked list contents */
  515.  
  516. DumpByNum(tree)
  517. NODE_PTR tree;
  518. {
  519.     if ((detail == 1) || (detail ==    2))
  520.         while (tree != NULL) {
  521.             printf("%-60.60s %5d (%0.2f%%)\n", tree->data, tree->hits, 
  522.                 (float)100.0*tree->hits/(float) total_hits);
  523.             if (detail == 2)
  524.                 DumpDetailList(tree->llist);
  525.             tree = tree->left;
  526.     }
  527. }
  528.  
  529. /*******************************/
  530. /* Dump    out Detail list    for each node->llist of    the tree*/
  531.  
  532. DumpDetailList(list)
  533. LIST_PTR list;
  534. {
  535.     while (list != NULL) {
  536.         printf("   %-47.47s %5d\n", list->data,    list->hits);
  537.         list = list->next;
  538.     }
  539. }
  540.  
  541. /*******************************/
  542. /* Dump    out cruft list and strip \n off    the end    so our report */
  543. /* looks nice. Naughty gopherd....*/
  544.  
  545. DumpCruftList(list)
  546. LIST_PTR list;
  547. {
  548. int linelen;
  549.     while (list != NULL) {
  550.         linelen=strlen(list->data);
  551.         if (list->data[linelen - 1]=='\n') 
  552.             list->data[linelen - 1]='\0';
  553.         printf("%-70.70s %5d\n", list->data, list->hits);
  554.         list = list->next;
  555.     }
  556. }
  557.  
  558. /*******************************/
  559. /* Add item to detail list internal to node*/
  560.  
  561. InsertDetail(list,element)
  562. LIST_PTR *list;
  563. char *element;
  564. {
  565. LIST_PTR temp, temp2;
  566. int i;
  567.     if (*list == NULL) {
  568.         temp = (LIST_PTR) malloc(sizeof(NODE_LIST));
  569.         if (temp) {
  570.             temp->next = NULL;
  571.             temp->hits = 1;
  572.             if (!(temp->data = malloc(strlen(element)+1))) {
  573.                 fprintf(stderr, "ERROR: Out of memory in InsertDetail\n");
  574.                 exit(1);
  575.             }
  576.             else {
  577.                 strcpy(temp->data, element);
  578.                 *list=temp;
  579.             }
  580.         }
  581.         else
  582.             printf("Memory error in    InsertDetail()\n");
  583.     }
  584.     else {
  585.         i=strcmp(element, (*list)->data);
  586.         if (i >    0) {
  587.             temp = (LIST_PTR) malloc(sizeof(NODE_LIST));
  588.             temp->hits = 1;
  589.             if (!(temp->data = malloc(strlen(element)+1))) {
  590.                 fprintf(stderr, "ERROR: Out of memory in InsertDetail 2\n");
  591.                 exit(1);
  592.             }
  593.             else {
  594.                 strcpy(temp->data, element);
  595.                 temp->next = *list;
  596.                 *list=temp;
  597.             }
  598.         }
  599.         else if    (i == 0) {
  600.             ++(*list)->hits;
  601.         }
  602.         else {
  603.             temp= *list;
  604.             temp2=(*list)->next;
  605.             while (temp2 !=    NULL) {
  606.                 i=strcmp(element, temp2->data);
  607.                 if (i >    0) {
  608.                     temp->next = (LIST_PTR)    malloc(sizeof(NODE_LIST));
  609.                     temp->next->next=temp2;
  610.                     if (!(temp->next->data = malloc(strlen(element)+1))) {
  611.                         fprintf(stderr, "ERROR: Out of memory in InsertDetail 3\n");
  612.                         exit(1);
  613.                     }
  614.                     else {
  615.                         strcpy(temp->next->data,element);
  616.                         temp->next->hits=1;
  617.                         return;
  618.                     }
  619.                 }
  620.                 else if    (i == 0) {
  621.                     ++temp2->hits;
  622.                     return;
  623.                 }
  624.                 else {
  625.                     temp=temp2;
  626.                     temp2=temp->next;
  627.                      }
  628.             }
  629.             temp->next = (LIST_PTR)    malloc(sizeof(NODE_LIST));
  630.             temp->next->next = NULL;
  631.             if (!(temp->next->data = malloc(strlen(element)+1))) {
  632.                 fprintf(stderr, "ERROR: Out of memory in InsertDetail 4\n");
  633.                 exit(1);
  634.             }
  635.             else {
  636.                 strcpy(temp->next->data,element);
  637.                 temp->next->hits=1;
  638.             }
  639.         }
  640.        }
  641.     
  642. }
  643.                 
  644. /*********************************************************************/
  645. /*** Plotting routines
  646.  ***/                    
  647. PlotByMonth0()
  648. {
  649. int ointday,ointmonth,intday,intmonth;
  650. int points,dtotal;
  651. char line[2048];
  652.  
  653.         intmonth=0;
  654.         intday=0;
  655.         fgets(line, 2048,stdin);
  656.         sscanf(line, "%s %s %s %s %s %s %s : %[^\n]",
  657.                         day, month, date, hours, year, pid, hostname,
  658.                         message2);
  659.         ointday=atoi(date);
  660.         fprintf(stderr,"set xtics (\"%s/%s\" 2,",month,date);
  661.         points = 1;
  662.         while (!feof(stdin)) {
  663.                 fgets(line, 2048, stdin);
  664.                 sscanf(line, "%s %s %s %s %s %s %s : %[^\n]",
  665.                         day, month, date, hours, year, pid, hostname,
  666.                         message2);
  667.                 intday=atoi(date);
  668.                 if (!strcmp(month,"Jan"))
  669.                         intmonth=1;
  670.                 else
  671.                 if (!strcmp(month,"Feb"))
  672.                         intmonth=2;
  673.                 else
  674.                 if (!strcmp(month,"Mar"))
  675.                         intmonth=3;
  676.                 else
  677.                 if (!strcmp(month,"Apr"))
  678.                         intmonth=4;
  679.                 else
  680.                 if (!strcmp(month,"May"))
  681.                         intmonth=5;
  682.                 else
  683.                 if (!strcmp(month,"Jun"))
  684.                         intmonth=6;
  685.                 else
  686.                 if (!strcmp(month,"Jul"))
  687.                         intmonth=7;
  688.                 else
  689.                 if (!strcmp(month,"Aug"))
  690.                         intmonth=8;
  691.                 else
  692.                 if (!strcmp(month,"Sep"))
  693.                         intmonth=9;
  694.                 else
  695.                 if (!strcmp(month,"Oct"))
  696.                         intmonth=10;
  697.                 else
  698.                 if (!strcmp(month,"Nov"))
  699.                         intmonth=11;
  700.                 else
  701.                 if (!strcmp(month,"Dec"))
  702.                         intmonth=12;
  703.                 if (intday !=  ointday) {
  704.                         ++points;
  705.                         printf("%d %d\n",points,dtotal);
  706.                         if ((intday == 1) || (intday == 15) || (intmonth != ointmonth)) 
  707.                                 fprintf(stderr,"\"%s/%s\" %d,",month,date,points);
  708.                         dtotal = 1;
  709.                 } else  {
  710.                         ++dtotal;
  711.                 }
  712.                 ointday=intday;
  713.                 ointmonth=intmonth;
  714.         }
  715.         fprintf(stderr,"\"\" %d)\n",points);
  716. /***
  717.  *** Put your own gnuplot directives here. These are the ones I like but
  718.  *** you can (and should) edit them to make it work for you.
  719.  ***/
  720.         fprintf(stderr,"set data style linespoints\n");
  721.         fprintf(stderr,"set tics out\n");
  722.         fprintf(stderr,"set grid\n");
  723.         fprintf(stderr,"set title \"Gopher Usage\"\n");
  724. }
  725.  
  726.  
  727. /*******************************/
  728. /*** Dispatch appropriate plot based on -p argument
  729.  ***/
  730. Plotter(plot_num)
  731. int plot_num;
  732. {
  733.     switch (plot_num) {
  734.         case 0:
  735.             PlotByMonth0();
  736.             break;
  737.             
  738.         /* Add additional plot routines here */
  739.         
  740.         default:
  741.             fprintf(stderr, "ERROR: Invalid plot number (%d)\n", plot_num);
  742.             exit(1);
  743.             break;
  744.     }
  745. }
  746.  
  747.  
  748. /*******************************/
  749. /* Show    all the    stats gleaned from the log file    */
  750. /* Aint    this ugly? Aint    I lazy?    */
  751.  
  752. ShowStats()
  753. {
  754.     printf("Detail level:");
  755.     if (detail == 0) printf(" Totals only\n");
  756.     else if    (detail    == 1) printf(" Host and    Document totals    only\n");
  757.     else if    (detail    == 2) printf(" Host and    Document detail    plus totals\n");
  758.     else if    (detail    == 3) printf(" Exception/Problem Report    only\n");
  759.     printf("Report Period: %s to %s\n", start_date,    stop_date);
  760.     if ((detail != 0) && (detail !=3) && USELESS) {
  761.         printf("=========================================================\n");
  762.         printf("\nAll Hosts:\n-----------------------------\n");
  763.     }
  764.     DumpStats(hosts);
  765.     if ((detail != 0) && (detail !=    3)) {
  766.         printf("=========================================================\n");
  767.         printf("Most Active Hosts:\n-----------------------------\n");
  768.         DumpByNum(by_num);
  769.     }
  770.     printf("------------------------\n");
  771.     if (detail !=3)     {
  772.         printf("Total Hosts:       %d\n", total_nodes);
  773.         printf("Total Connections: %d\n", total_hits);
  774.     }
  775.     if ((detail != 0) && (detail !=3) && USELESS) {
  776.         printf("=========================================================\n");
  777.         printf("All Data Accesses:\n-----------------------------\n");
  778.         }
  779.     DumpStats(docs);
  780.     if ((detail != 0) && (detail !=3)) {
  781.         printf("=========================================================\n");
  782.         printf("Most Popular Data:\n-----------------------------\n");
  783.         DumpByNum(by_num);
  784.     }
  785.     if (detail !=3)
  786.         printf("------------------------\n");
  787.     if ((detail == 2) || (detail ==    3)) {
  788.         printf("=========================================================\n");
  789.         printf("Exception/Problem Report\n");
  790.         printf("NOTE: THESE ENTRIES MAY    DENOTE A SERVER    PROBLEM. THEY SHOULD BE    LOOKED OVER!\n");
  791.         DumpCruftList(cruft);
  792.         printf("------------------------\n");
  793.     }
  794.     printf("Total Data Accesses: %d\n", total_hits);
  795. }
  796.